package com.git.hui.yinshua.common;

import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.RuntimeUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * for test
 *
 * @author YiHui
 * @date 2024/9/13
 */
@Slf4j
public class MemUtil {
    /**
     * 判断可用内存是否够用，默认当剩余可用内存大于 32% 是
     *
     * @param rate 剩余内存可用的比例，如果为100,则一直返回false； 如果为0，则一直可用
     * @return true 表示剩余内存不够
     */
    public static boolean availableEnable(int rate) {
        AtomicBoolean available = new AtomicBoolean(true);
        List<MemoryPoolMXBean> list = ManagementFactory.getMemoryPoolMXBeans();
        list.forEach(s -> {
            if (s.getType() == MemoryType.HEAP) {
                MemoryUsage usage = s.getUsage();
                long use = usage.getUsed();
                long total = usage.getMax();
                BigDecimal r = BigDecimal.valueOf(use * 100)
                        .divide(BigDecimal.valueOf(total), RoundingMode.CEILING)
                        .setScale(2, RoundingMode.CEILING);
                log.info("jvm内存分析: use/total = {} / {} = {} ? {}", DataSizeUtil.format(use), DataSizeUtil.format(total), r, rate);
                if (100 - r.doubleValue() < rate) {
                    available.set(false);
                }
            }
        });

        return available.get();
    }

    /**
     * 获取内存信息
     *
     * @return 内存信息
     */
    public static String memInfo() {
        try {
            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            // JVM用于对象分配的堆的当前内存使用情况
            MemoryUsage usage = memoryMXBean.getHeapMemoryUsage();

            long use = usage.getUsed();
            long total = usage.getMax();
            float r = 100 * use / (float) total;
            return "jvm内存分析: use/total=" + DataSizeUtil.format(use) + " / " + DataSizeUtil.format(total) + " = " + r + " 待回收: " + memoryMXBean.getObjectPendingFinalizationCount();
        } catch (Exception e) {
            log.info("获取内存信息异常: ", e);
        }
        return null;
    }

    public static String memInfoV2() {
        try {
            long use = RuntimeUtil.getTotalMemory() - RuntimeUtil.getFreeMemory();
            long total = RuntimeUtil.getMaxMemory();
            float r = 100 * use / (float) total;
            return "jvm内存分析: use/total=" + DataSizeUtil.format(use) + " / " + DataSizeUtil.format(total) + " = " + r;
        } catch (Exception e) {
            log.info("获取内存信息异常: ", e);
        }
        return null;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            long start = System.nanoTime();
            System.out.println("Mem方式" + memInfo() + " ==> cost: " + (System.nanoTime() - start));
            start = System.nanoTime();
            System.out.println("Runtime方式" + memInfoV2() + " ==> cost: " + (System.nanoTime() - start));
        }
    }
}
